To achieve more than the simplest "Hello World" task in any programming language, you need to get into some real programming. Just as trying to hold a conversation in French knowing only Bonjour can be somewhat limiting, programming in VBScript can be difficult knowing only Alert "Hello World".
To write scripts or programs that achieve a goal or provide a solution, you first need to clearly define the task at hand. Because VBScript is a logical and easy-to-use language, you will soon see that the definition you have come up with for your problem can be translated directly into a program.
But writing modern event-driven programs with VBScript is not a straightforward, start-to-finish affair. Many times, you need the program to make decisions and, based on that decision, maybe jump to another part of the program. Or, perhaps, a calculation is required to produce a value you use regularly in the program, so your program jumps off in another direction to get that value and then comes back to continue. This is where managing program flow becomes vital.
In this chapter, you'll see the main constituents of program flow. Program flow is dictated by calls to functions and procedures, loops, and decisions-parts of the program that force execution to be either diverted somewhere else in the program or held in a certain part for a given period. Before this gets too cryptic, let's move on and see this in action.
Subroutines are small, almost self-contained programs that are called by another part of the program as they are required. The term subroutine can be thought of as a general term for the individually defined sections of the overall script.
Subroutines in VBScript include the following:
Functions are separate subroutines that return a value-simple as that. Declaring a function is very straightforward:
Function myFunctionName() ..... End Function
You use the keyword Function, followed by the name you've given to the function. The parentheses are used to hold the variable names for any values being passed into the function from outside, which is covered later in this section. To complete the function definition, use the words End Function. The following is a quick example, with the result shown in Figure 9.1.
Figure 9.1 : The custom function (myfunction.htm) in the browser.
<HTML> <HEAD> <TITLE>My Function</TITLE> <SCRIPT LANGUAGE="vbscript"> Sub myButton_OnClick myVar = Document.Form1.Input.Value Document.Form1.Output.Value = myFunction(myVar) End Sub Function myFunction(ByVal AnyValue) myFunction = AnyValue & " added by my function" End Function </SCRIPT> </HEAD> <BODY BGCOLOR="white"> <CENTER> <FORM NAME="Form1"> Input <INPUT TYPE="text" NAME="Input"><P> <INPUT TYPE="button" NAME="myButton" VALUE="Click Me"><P> Output <INPUT TYPE="text" NAME="Output" SIZE=40></FORM </CENTER> </BODY> </HTML>
In this example, execution of the script commences when you click the button. This fires an OnClick event, which is handled by the myButton_OnClick event handler, shown here:
Sub myButton_OnClick myVar = Document.Form1.Input.Value Document.Form1.Output.Value = myFunction(myVar) End Sub
The value in the Input text box is copied into the myVar variable. The next line basically says to the program, "Go and do myFunction, take myVar with you and bring back the result; then show that result in the Output text box." So, off it goes to myFunction, taking myVar with it. Here's the myFunction function:
Function myFunction(ByVal AnyValue) myFunction = AnyValue & " added by my function" End Function
This function has been defined to receive one variable, which can be any variable. The ByVal keyword tells the scripting engine that it wants to receive just the value of the passed variable. If you try to call this function without any variables (or arguments), like
x = myFunction()
or if you call it with more than one argument, like
x = myFunction(y, a, I, strMyString)
you generate a runtime error. The number of arguments (or variables) must be the same. The names you use for the argument are irrelevant, but the order in which they appear is the same. Here is an example:
a = 10 b = 20 c = 30 d = 40 x = anyFunction(a,b,c,d) Function anyFunction(e,f,g,h)
Within the anyFunction function, the values are e = 10, f = 20, g = 30, and h = 40.
To return the result of the function to the code that called it, you use the function name as the left side of an assignment, like this:
myFunction = AnyValue & " added by my function"
When the execution reaches the End Function, the value that has been assigned to the function is passed back to the calling script as the result.
But why not just put the code in line with the rest of the program? Well, it really depends on what you are trying to achieve. Let's say you use a particular calculation in many different parts of the program. Each time you use the calculation, you have to enter the same lines of code. It would be much easier to enter the code once in a function, and then call the function each time you need to use the calculation. Another benefit of a function is that it makes the code easier to read. Separating the code that performs a calculation makes for a tidier, less cluttered appearance. Look at the following "before and after" example:
<SCRIPT LANGUAGE="vbscript"> Sub cmdButton1_OnClick x = CDbl(Document.Form1.Text1.Value) y = CDbl(Document.Form1.Text2.Value) z = x * 34 + y b = z / (35 * 9) + 1 i = b ^ 789 - 93 Document.Form1.Text3.Value = CStr(i) End Sub Sub cmdButton2_OnClick x = CDbl(Document.Form1.Text4.Value) y = CDbl(Document.Form1.Text5.Value) z = x * 80 + y b = z / (35 * 9) + 1 i = b ^ 789 - 93 Document.Form1.Text6.Value = CStr(i) End Sub Sub cmdButton3_OnClick x = CDbl(Document.Form1.Text7.Value) y = 989 z = x * 20 + y b = z / (35 * 9) + 1 i = b ^ 789 - 93 Document.Form1.Text9.Value = CStr(i) End Sub </SCRIPT>
In this totally imaginary script, each of three buttons has a similar event handler. But notice the subtle differences in each one. The following is how it could be rescripted using a single function:
<SCRIPT LANGUAGE="vbscript"> Function myFunction(ByVal x, ByVal y, ByVal v) x = CDbl(x) y = CDbl(y) z = x * v + y b = z / (35 * 9) + 1 i = b ^ 789 - 93 myFunction = CStr(i) End Function Sub cmdButton1_OnClick Document.Form1.Text3.Value = myFunction(Document.Form1.Text1.Value, åDocument.Form1.Text2.Value, 34) End Sub Sub cmdButton2_OnClick Document.Form1.Text6.Value = myFunction(Document.Form1.Text4.Value, åDocument.Form1.Text5.Value, 80) End Sub Sub cmdButton3_OnClick Document.Form1.Text9.Value = myFunction(Document.Form1.Text7.Value, 989, 20) End Sub </SCRIPT>
Not only does it look tidier, but it is also easier to maintain. Any modification to the formula needs to be made in only one place rather than three, which reduces the chance of error.
A custom procedure is a subroutine that doesn't return a value. Like functions, procedures can accept variables from other parts of the program. To declare a custom procedure, you use the Sub keyword, followed by the name of the procedure.
Sub myProcedure() .... End Sub
You can use two types of syntax to call a custom procedure. The first method is to use the keyword Call, like this:
Call myProcedure()
If you use the keyword Call, you must use parentheses around the argument list or use empty parentheses. The other method is to simply use the procedure name without the word Call, like this:
myProcedure
If you omit the keyword Call, you cannot use parentheses around your argument list.
The following example uses both methods. The result is shown in Figure 9.2.
Figure 9.2 : The custom procedure, proc.htm, in the browser.
<HTML> <HEAD> <TITLE>My Custom Procedure</TITLE> <SCRIPT LANGUAGE="vbscript"> Sub Button1_OnClick Call DoComplexMessage("First Message") End Sub Sub Button2_OnClick DoComplexMessage "Second Message" End Sub Sub DoComplexMessage(ByVal Message) Dim CRLF Dim strTitle Dim strMainMessage CRLF = Chr(10) & Chr(13) strTitle = "My Custom Procedure" strMainMessage = "Hello this is the " & Message & CRLF strMainMessage = strMainMessage & "This is my procedure to show " & CRLF strMainMessage = strMainMessage & "a message box which is similar " & CRLF strMainMessage = strMainMessage & "from both buttons" x = MsgBox(strMainMessage,0,strTitle) End Sub </SCRIPT> </HEAD> <BODY BGCOLOR="white"> <CENTER> <INPUT TYPE="button" NAME="Button1" VALUE="Button 1"> <INPUT TYPE="button" NAME="Button2" VALUE="Button 2"> </CENTER> </BODY> </HTML>
Both event handlers for the buttons call the DoComplexMessage procedure. One uses Call and parentheses, and the other simply uses the procedure name. As you can clearly see, the use of a custom procedure in this example removes the need for you to write the same code more than once.
The ActiveX Control Pad enables you to quickly create custom procedures and functions, and it also makes it easy to add the calls to your custom procedures and functions.
To see how this works, let's re-create the example used in the last section using the ActiveX Control Pad.
Dim strTitle Dim strMainMessage CRLF = Chr(10) & Chr(13) strTitle = "My Custom Procedure" strMainMessage = "Hello this is the " & Message & CRLF strMainMessage = strMainMessage & "This is my procedure to show " & CRLF strMainMessage = strMainMessage & "a message box which is similar " & åCRLF strMainMessage = strMainMessage & "from both buttons" x = MsgBox(strMainMessage,0,strTitle)
<HTML> <HEAD> <SCRIPT LANGUAGE="VBScript"> <!-- Sub DoComplexMessage(ByVal Message) Dim CRLF Dim strTitle Dim strMainMessage CRLF = Chr(10) & Chr(13) strTitle = "My Custom Procedure" strMainMessage = "Hello this is the " & Message & CRLF strMainMessage = strMainMessage & "This is my procedure to show " å & CRLF strMainMessage = strMainMessage & "a message box which is similar " å & CRLF strMainMessage = strMainMessage & "from both buttons" x = MsgBox(strMainMessage,0,strTitle) end sub --> </SCRIPT> <TITLE>My Custom Procedure</TITLE> </HEAD> <BODY BGCOLOR="white"> <CENTER> <INPUT LANGUAGE="VBScript" TYPE=button VALUE="Button 1" åOncLICK="call DoComplexMessage("First Message")" NAME="Button1"> <INPUT LANGUAGE="VBScript" TYPE=button VALUE="Button 2" åOncLICK="call DoComplexMessage("Second Message")" NAME="Button2"> </CENTER> </BODY> </HTML>
Note that the custom procedure code is identical to the one you
created manually earlier. However, the Script Wizard places event
handlers for HTML Intrinsic controls within the HTML definition
of the control. Save the file and test it in the browser.
NOTE |
You can also create custom functions using the ActiveX Script Wizard. Follow the previous instructions, and simply replace the word Sub with Function. When the Script Wizard generates the code, it will automatically place End Function rather than End Sub at the end of the script. |
Adding some pseudo-intelligence to your script is possible only if you can enable your script to make decisions. You can add decision-making capabilities in two ways.
The If...Then conditional statement is the most widely used construct in any programming language. It is easy and quick to use and enables you to branch the program based on the result of the condition, like this:
If myVariable = yourVariable Then Alert "got a match" End
If...Then statements can also be nested, which means you can have a condition that is tested only if the condition of the first statement is true. Here is an example:
If myVariable = yourVariable Then If aVariable = bVariable Then Alert "Both sets match" End If End If
For the code within the conditional statement to execute, the condition must evaluate True.
if x = 10 then Alert "yes, x does equal 10" end if
But what happens if it evaluates to False? Well, normally execution continues with the code directly after the End If statement. However, you can add an Else statement within the condition, which makes the code execute only if the condition is False. Here is an example:
If x = 10 then Alert "Yes, x does equal 10" Else Alert "No, x does not equal 10" End If
You can even add a further condition within the Else section. Just use the ElseIf keyword, like this:
If x = 10 then Alert "Yes, x does equal 10" ElseIf x = 20 Then Alert "x does not equal 10 but it equals 20" Else Alert "x does not equal 10 or 20" End If
You can turn the condition on its head and have the code execute only if the condition evaluates to False. This is done by including the negation operator Not.
If Not x = 10 Then Alert "Sorry but x does not equal 10" End If
Note that, in truth, the overall statement still evaluates to True. Essentially, the statement says, "Does x not equal 10? Yes, it doesn't."
The other type of conditional statement you have at your disposal is the Select Case block. With Select Case, you start with a known value and then use the Case statement to compare whether the case variable matches the selection variable. If the comparison evaluates to true, the line following Case is executed. After execution, the program continues with the line following End Select.
Select Case x Case 5 Alert "x equals 5" Case 10 Alert "x equals 10" Case 15 Alert "x equals 15" End Select
Again, let's look at how you can have at least one line of the block execute no matter what the result. You use Case Else, like this:
Select Case x Case 5 Alert "x equals 5" Case 10 Alert "x equals 10" Case 15 Alert "x equals 15" Case Else Alert "I dont care what value x is but its not 5, 10 or 15" End Select
NOTE |
Unlike Select Case in Visual Basic, the VBScript version does not allow statements like Case Is < 8 or Case Is 10 To 100. All values for the Case statements must be explicit, which restricts its usage drastically. |
What do you do if you need to execute the same section of code many times over, possibly with a slight change to the code? You could write the code over and over again, like this:
x = 0 Document.Write x Document.Write x + 1 Document.Write x + 2 Document.Write x + 3 Document.Write x + 4 Document.Write x + 5
This could continue on, and copying and pasting it wouldn't take too long to reach 100! But there's a much easier method to achieve the same result. It's known as a loop.
VBScript gives you two ways in which you can repeat the same code as many times as you want:
A For...Next loop enables you to repeat execution of the code held within the loop a given number of times. You specify the upper and lower parameters of the loop counter, and the scripting engine increments the loop counter automatically as the loop is executed.
For x = 1 to 100 do some code 100 times Next
NOTE |
VB programmers should keep in mind that in VBScript, you can use only Next. You do not have the option to use the old Next x as you do in VB4. |
By default, the loop counter is incremented by one every time the program reaches the Next statement, until the upper limit is reached, at which point the program continues execution with the line following Next.
Let's have a look at a few variations on the For...Next theme. First, what if you want the counter to increment in reverse, or maybe increment by more than one each time? There's a special keyword called Step. Step is used to change the behavior of the increment. If Step is negative, the loop goes backward, like so:
For x = 100 to 0 Step -1 Do something 100 times Next
In this example, x starts at 100 and is reduced by 1 with every loop until it reaches 0, at which point the loop is terminated. Step can be any number, and that number then becomes the increment.
For x = 0 to 100 Step 2 Do something 50 times Next
Second, what if you want to initially loop a certain number of times, but jump out of the loop if a particular condition is met? For this, you use Exit For. Exit For takes the execution out of the loop and resumes the program at the line immediately following the Next statement.
For x = 0 to 50 y = y + 1 If y = z then Exit For End If Next
Another way you can repeat the same code over and over is to use a Do...Loop statement, like this:
Do code to execute for ever Loop
But, actually, it's not like this at all. If you wrote that into your script, your script would never finish. You need to give the loop a condition so that it knows when to stop repeating. The two conditions are While and Until.
A Do While loop repeats while a condition is True, as in the following example:
x = 2 Do While x < 10 x = x + 1 Loop
A Do Until loop repeats until a condition is True, as in the following example:
Do Until x = 10 x = x + 1 Loop
As with the For...Next loop, you have several options that you can use with the Do...Loop statement. The first is Exit Do. Again, this is to allow an exit route for your program in case the need arises.
Do While x < 100 x = x + 1 z = z - 1 If z = 50 Exit Do End if Loop
The next option is to place the While or Until on the same line as Loop, rather than on the same line as Do, like this:
Do x = x + 1 Loop Until x = 100
The difference is that placing While or Until next to Loop forces the statement block to be executed at least once. If the condition is placed next to Do, and the condition is True as the program arrives at the statement block, then the loop is not executed. Here is an example:
x = 200 Do While x < 100 This code never executes Loop
However, if the code was rewritten like the following, the code executes once:
x = 200 Do This Code executes only once Loop While x < 100
In this chapter, you've been through the main language components that enable you to control the flow within your script. From defining subroutines and functions, to decision-making statements, and finally how to execute code over and over. Here's a brief summary:
Now you know how to create scripts that can make decisions, branch to other parts of the script, repeat sections of code, and generally perform like they know what they're doing. You can add even more functionality to your scripts by looking at the following chapters:
| How do you decide when to subdivide a program into smaller sections? |
| Many of the reasons for creating separate subroutines and functions will give you an idea about when it is right to create a separate subroutine. Subroutines save coding. If you find yourself coding the same lines over and over, you probably need a subroutine. If you have a routine that returns a value, and that value might (now or in future) be needed by several parts of the program, or if the routine to produce the value is more than a few lines of code, I would suggest that it be placed in its own function. |